package com.fmy.jurisdiction.config.security;

import com.fmy.jurisdiction.core.commons.kits.AdminPwdSecureKit;
import com.fmy.security.config.SecurityConfigAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * @author Mr.fmy
 * @version 1.0.0
 * @ClassName SecurityConfig.java
 * @Description TODO Security配置类
 * @createTime 2019年07月06日 17:10:00
 */
@Configuration
public class SecurityConfig extends SecurityConfigAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 登录盐值储存
     */
    public final static ThreadLocal<String> THREADLOCAL_SALT = new ThreadLocal<>();

    private final String[] permit_urls = new String[]{"/login/**"}; //不登录可访问接口
    private final String[] authenticated_urls = new String[]{"/**"}; //必须登录才可访问接口 与 permit_urls 形成 差异关系
    private final String login_url = "/login/auth";//登录授权 url

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry
                = http.authorizeRequests();
        registry.requestMatchers(CorsUtils::isPreFlightRequest).permitAll();//让Spring security放行所有preflight request

        http.cors().and().csrf().disable()
                .authorizeRequests()
                .antMatchers(permit_urls).permitAll()//login路径下的接口可以自由访问
                .antMatchers(authenticated_urls).authenticated();
        http.formLogin().loginPage(login_url);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return AdminPwdSecureKit.md5(charSequence.toString(), THREADLOCAL_SALT.get());
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return AdminPwdSecureKit.md5(charSequence.toString(), THREADLOCAL_SALT.get()).equals(s);
            }
        });
    }

    /**
     * 自定义配置
     */
    @Override
    protected void configure(Config config) {
//        config.setMaxRegister(2);//设置同一用户并发量
//        config.getLoginTypeFilter().setKey("login_type")//设置登录时 获取登录方式的参数、默认login_type
//                .setRequestMatcher("/login/auth", HttpMethod.POST)//设置拦截的登录地址
//                .setTypes("app", "web", "we_caht");//设置默认的登录类型
////        默认不拦截路径 /login/** 默认拦截路径 /**
        config.getTokenContextHolderFilter()
                .notUrls(permit_urls)//不拦截路径
                .url(authenticated_urls) //拦截路径 notUrls或url配置一个也可以、如果两个都配置那么之间的关系就是 and
                .buildMatcher(); //notUrls和url存在一个, 就需要调用该方法
//                .setTokenKey("Authorization");//获取token在请求头的key值
    }

    /**
     * 处理需要被Security拦截的url跨域问题
     */
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }

}
